# -*- coding: utf-8 -*-
# created on 2017/01/05
#

from mathsolver.functions.base import *
from mathsolver.functions.base.base import new_latex
from mathsolver.functions.xiangliang.Vector_Fundamental import vector_xiangs
from mathsolver.functions.process import ProcessExpression
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve, MathematicaSimplify
from mathsolver.functions.xiangliang.basic import (XLJiHeConditionEqTransform, xl_search_multiple, XLJudgeAxis,
                                                   XLXiangs, XLAxisConditionEqTransform, xl_judge_sanjiao_vector,
                                                   XLSanJiaoEqsKnownUpdate, XLJiHeConditionExprTransform,
                                                   xl_solutions_subs, VectorAxisKnownUpdate, VectorAbsKnownUpdate)
from mathsolver.functions.xiangliang.Vector_Fundamental import vector_get_abs, vector_get_angles, vector_axis_names


# 坐标法：向量运算: 不含equations
class XLGetExpress001(BaseFunction):
    def solver(self, *args):
        assert len(args) == 1
        known = self.known
        if 'Vequations' in known:
            veqs = known['Vequations']
            assert not veqs
        target = args[0].sympify()
        flag = XLJudgeAxis(known).solver(target).output[0].sympify()
        assert flag
        answer = ProcessExpression(known).solver(args[0]).output[0].sympify()
        self.steps.append(["", "\\therefore %s = %s" % (new_latex(target), new_latex(answer))])
        self.output.append(BaseVector(answer))
        self.label.add("向量运算-坐标法")
        return self


class XLGetExpress002(BaseFunction):
    """
    不含equations, 向量名含两个字母
    已知点A(1,3),B(4,-1),求向量\\overrightarrow{AB}
    """
    def solver(self, *args):
        assert len(args) == 1
        known = self.known
        assert 'Vequations' not in known
        assert isinstance(args[0], BaseVector)
        vector = sympify(args[0].value)
        vector_name = vector.args[0]
        assert len(str(vector_name)) == 2
        vector_axis_name = str("Axis_")
        vector_axis_name = vector_axis_name + str(vector_name)
        if vector_axis_name in self.known:
            pass
        else:
            left_p, right_p = str(vector_name)
            if left_p in self.known:
                left_p_value = self.search(left_p)
                left_p_value = left_p_value.sympify()
            else:
                raise Exception("to do")
            if right_p in self.known:
                right_p_value = self.search(right_p)
                right_p_value = right_p_value.sympify()
            else:
                raise Exception("to do")
            vector_value = (right_p_value[0] - left_p_value[0], right_p_value[1] - left_p_value[1])
            known[vector_axis_name] = vector_value
        answer = ProcessExpression(known).solver(args[0]).output[0].sympify()
        self.steps.append(["", "\\therefore %s = %s" % (new_latex(vector), new_latex(answer))])
        self.output.append(BaseVector(answer))
        self.label.add("向量运算-坐标法")
        return self


# 坐标法：向量运算: 含equations
class XLGetExpress003(BaseFunction):
    def solver(self, *args):
        assert len(args) == 1
        known = self.known
        assert 'Vequations' in known
        veqs = known['Vequations']
        assert veqs
        if self.known['inequations']:
            for ineq in self.known['inequations']:
                left, op, right = ineq
                new_ineq = [sympify(left), op, sympify(right)]
                if new_ineq not in veqs:
                    veqs.append(new_ineq)
        if self.known['equations']:
            for eq in self.known['equations']:
                if eq not in veqs:
                    veqs.append(eq)
        if isinstance(args[0], BaseVector):
            target = sympify(args[0].value)
        else:
            target = args[0].sympify()
        flag = XLJudgeAxis(known).solver(target).output[0].sympify()
        assert flag
        vectors = XLXiangs(known).solver(target).output[0].sympify()
        vectors_axis_names = vector_axis_names(vectors)
        stepsolver = VectorAxisKnownUpdate(known).solver(vectors_axis_names)
        self.steps += stepsolver.steps
        new_known = stepsolver.output[0]
        condition_veqs = []
        for eq in veqs:
            if len(eq) == 2:
                new_eqs = XLAxisConditionEqTransform(new_known).solver(BaseEq(eq)).output[0].sympify()
            else:
                new_eqs = XLAxisConditionEqTransform(new_known).solver(BaseIneq(eq)).output[0].sympify()
            for new_eq in new_eqs:
                condition_veqs.append(new_eq)
        self.steps.append(["", "依题意，得"])
        if len(condition_veqs) == 1:
            self.steps.append(["", "%s" % BaseEq(condition_veqs[0]).printing()])
        else:
            self.steps.append(["", "%s" % BaseIneqs(condition_veqs).printing()])
        solutions = MathematicaSolve().solver(BaseIneqs(condition_veqs)).output[0]
        self.steps.append(["", "解得: %s" % solutions.printing()])
        condition_target = ProcessExpression(new_known).solver(BaseValue(str(target))).output[0].sympify()
        if isinstance(condition_target, tuple):
            left = condition_target[0]
            left_answers = xl_search_multiple(solutions.sympify(), left)
            assert left_answers
            left_values = []
            for left_ans in left_answers:
                left_value = left
                left_value = left_value.subs(left_ans)
                left_value = MathematicaSimplify().solver(BasePoly(left_value)).output[0].sympify()
                left_values.append(left_value)
            left_values = set(left_values)
            left_values = list(left_values)
            right = condition_target[1]
            right_answers = xl_search_multiple(solutions.sympify(), right)
            assert right_answers
            right_values = []
            for right_ans in right_answers:
                right_value = right
                right_value = right_value.subs(right_ans)
                right_value = MathematicaSimplify().solver(BasePoly(right_value)).output[0].sympify()
                right_values.append(right_value)
            right_values = set(right_values)
            right_values = list(right_values)
            target_values = [(ll, r) for ll, r in zip(left_values, right_values)]
            self.steps.append(["", "\\therefore %s" % " 或 ".join(
                ["%s = %s" % (new_latex(target), new_latex(v)) for v in target_values])])
        else:
            target_values = xl_solutions_subs(solutions, condition_target)
            target_values = set(target_values)
            target_values = list(target_values)
            self.steps.append(["", "\\therefore %s" % " 或 ".join(
                ["%s = %s" % (new_latex(target), new_latex(v)) for v in target_values])])
        self.label.add("向量运算-坐标法")
        return self


class XLGetExpress004(BaseFunction):
    """
    坐标法：向量运算：含equations
    已知向量\\overrightarrow{OA}⊥\\overrightarrow{AB},{|{\\overrightarrow{OA}}|}=3,
    则\\overrightarrow{OA}• \\overrightarrow{OB}=
    """
    def solver(self, *args):
        assert len(args) == 1
        known = self.known
        assert 'Vequations' in known
        veqs = known['Vequations']
        assert veqs
        if isinstance(args[0], BaseVector):
            target = sympify(args[0].value)
        else:
            target = args[0].sympify()
        judge_eqs = []
        judge_eqs.extend(veqs)
        judge_eqs.append([target, S.Zero])
        flag = xl_judge_sanjiao_vector(judge_eqs)
        assert flag
        new_known = XLSanJiaoEqsKnownUpdate(known, judge_eqs)
        condition_veqs = []
        for eq in veqs:
            new_eqs = XLAxisConditionEqTransform(new_known).solver(BaseEq(eq)).output[0].sympify()
            condition_veqs.extend(new_eqs)
        self.steps.append(["", "依题意，得"])
        if len(condition_veqs) == 1:
            self.steps.append(["", "%s" % BaseEq(condition_veqs[0]).printing()])
        else:
            self.steps.append(["", "%s" % BaseIneqs(condition_veqs).printing()])
        solutions = MathematicaSolve().solver(BaseIneqs(condition_veqs)).output[0].sympify()
        self.steps.append(["", "解得: %s" % (BaseSymbolValue(solutions).printing())])
        condition_target = ProcessExpression(new_known).solver(BaseValue(str(target))).output[0].sympify()
        if isinstance(args[0], BaseVector):
            left = condition_target[0]
            left_answers = xl_search_multiple(solutions, left)
            assert left_answers
            left_values = []
            for left_answer in left_answers:
                new_left = left
                new_left = new_left.subs(left_answer)
                new_left = MathematicaSimplify().solver(BasePoly(new_left)).output[0].sympify()
                left_values.append(new_left)
            left_values = set(left_values)
            left_values = list(left_values)
            right = condition_target[1]
            right_answers = xl_search_multiple(solutions, right)
            assert right_answers
            right_values = []
            for right_answer in right_answers:
                new_right = right
                new_right = new_right.subs(right_answer)
                new_right = MathematicaSimplify().solver(BasePoly(new_right)).output[0].sympify()
                right_values.append(new_right)
            right_values = set(right_values)
            right_values = list(right_values)
            self.steps.append(["", "\\therefore%s为%s" % (new_latex(target), "或".join(
                ["(%s, %s)" % (new_latex(left_v), new_latex(right_v)) for left_v, right_v in
                 zip(left_values, right_values)]))])
            target_values = []
            for left_v, right_v in zip(left_values, right_values):
                target_values.append([left_v, right_v])
            self.output.append(BaseVector(target_values))
        else:
            answers = xl_search_multiple(solutions, condition_target)
            assert answers
            target_values = []
            for ans in answers:
                new_value = condition_target
                new_value = new_value.subs(ans)
                new_value = MathematicaSimplify().solver(BasePoly(new_value)).output[0].sympify()
                target_values.append(new_value)
            target_values = set(target_values)
            target_values = list(target_values)
            self.steps.append(
                ["\\therefore", " 或 ".join(["%s = %s" % (new_latex(target), new_latex(v)) for v in target_values])])
            self.output.append(BaseNumbers(target_values))
        self.label.add("向量运算-坐标法")
        return self


# 几何法：向量运算: 不含equations
class XLGetExpress005(BaseFunction):
    def solver(self, *args):
        assert len(args) == 1
        assert 'Vequations' in self.known
        known = self.known
        veqs = known['Vequations']
        condition_eqs = []
        abs_symbols = []
        c_angle_symbols = []
        for eq in veqs:
            new_eq = XLJiHeConditionEqTransform(known).solver(BaseEq(eq)).output[0].sympify()
            expr = new_eq[0] - new_eq[1]
            expr_abss = vector_get_abs(expr)
            if expr_abss:
                for expr_Abs in expr_abss:
                    abs_symbols.append(expr_Abs)
            expr_c_angles = vector_get_angles(expr)
            if expr_c_angles:
                for expr_CAngle in expr_c_angles:
                    c_angle_symbols.append(expr_CAngle)
            condition_eqs.append(new_eq)
        abs_symbols = set(abs_symbols)
        abs_symbols = list(abs_symbols)
        if abs_symbols:
            for Abs_symbol in abs_symbols:
                condition_eqs.append([Abs_symbol, '>', S.Zero])
        c_angle_symbols = set(c_angle_symbols)
        c_angle_symbols = list(c_angle_symbols)
        if c_angle_symbols:
            for CAngle_symbol in c_angle_symbols:
                condition_eqs.append([CAngle_symbol, '>=', -1])
                condition_eqs.append([CAngle_symbol, '<=', 1])
        stepsolver = MathematicaSolve().solver(BaseIneqs(condition_eqs))
        solutions = stepsolver.output[0]
        assert not solutions.sympify()
        target = args[0].sympify()
        new_target = XLJiHeConditionExprTransform(known).solver(BasePoly(target)).output[0].sympify()
        self.steps.append(["", "\\therefore %s = %s" % (new_latex(target), new_latex(new_target))])
        self.output.append(BaseNumber(new_target))
        self.label.add("向量运算-几何法")
        return self


# 几何法：向量运算: 含equations
class XLGetExpress006(BaseFunction):
    """
    设向量\\overrightarrow{a},\\overrightarrow{b}满足|\\overrightarrow{a}+\\overrightarrow{b}|=\\sqrt{10},
    |\\overrightarrow{a}-\\overrightarrow{b}|=\\sqrt{6},则\\overrightarrow{a}•\\overrightarrow{b}=()
    """
    def solver(self, *args):
        assert len(args) == 1
        assert 'Vequations' in self.known
        known = self.known
        veqs = known['Vequations']
        assert veqs
        target = args[0].sympify()
        flag = XLJudgeAxis(known).solver(target).output[0].sympify()
        assert not flag
        vectors = XLXiangs(known).solver(target).output[0].sympify()
        stepsolver = VectorAbsKnownUpdate(known).solver(vectors)
        self.steps += stepsolver.steps
        condition_eqs = []
        abs_symbols = []
        c_angle_symbols = []
        for eq in veqs:
            if len(eq) == 2:
                new_eq = XLJiHeConditionEqTransform(known).solver(BaseEq(eq)).output[0].sympify()
            else:
                new_eq = XLJiHeConditionEqTransform(known).solver(BaseIneq(eq)).output[0].sympify()
            if len(eq) == 2:
                expr = new_eq[0] - new_eq[1]
            else:
                expr = new_eq[0] - new_eq[2]
            if expr != 0 and expr.free_symbols:
                expr_abss = vector_get_abs(expr)
                if expr_abss:
                    for expr_Abs in expr_abss:
                        abs_symbols.append(expr_Abs)
                expr_c_angles = vector_get_angles(expr)
                if expr_c_angles:
                    for expr_CAngle in expr_c_angles:
                        c_angle_symbols.append(expr_CAngle)
                condition_eqs.append(new_eq)
        for index, eq in enumerate(condition_eqs):
            if len(eq) == 2:
                expr = eq[0] - eq[1]
            else:
                expr = eq[0] - eq[2]
            expr_vector_xiangs = vector_xiangs(expr)
            if expr_vector_xiangs:
                if len(eq) == 2:
                    new_eq = [eq[0] ** 2, eq[1] ** 2]
                else:
                    raise Exception("to do")
                new_eq = XLJiHeConditionEqTransform(known).solver(BaseEq(new_eq)).output[0].sympify()
                expr = new_eq[0] - new_eq[1]
                expr_abss = vector_get_abs(expr)
                if expr_abss:
                    for expr_Abs in expr_abss:
                        abs_symbols.append(expr_Abs)
                expr_c_angles = vector_get_angles(expr)
                if expr_c_angles:
                    for expr_CAngle in expr_c_angles:
                        c_angle_symbols.append(expr_CAngle)
                condition_eqs[index] = new_eq
            else:
                condition_eqs[index] = eq
        abs_symbols = set(abs_symbols)
        abs_symbols = list(abs_symbols)
        if abs_symbols:
            for Abs_symbol in abs_symbols:
                condition_eqs.append([Abs_symbol, '>=', S.Zero])
        c_angle_symbols = set(c_angle_symbols)
        c_angle_symbols = list(c_angle_symbols)
        if c_angle_symbols:
            for CAngle_symbol in c_angle_symbols:
                condition_eqs.append([CAngle_symbol, '>=', -1])
                condition_eqs.append([CAngle_symbol, '<=', 1])
        if condition_eqs:
            self.steps.append(["", "依题意，得"])
            self.steps.append(["", "%s" % (BaseIneqs(condition_eqs).printing())])
            stepsolver = MathematicaSolve().solver(BaseIneqs(condition_eqs))
            solutions = stepsolver.output[0]
            assert solutions.sympify()
            self.steps.append(["", "解得: %s" % (solutions.printing())])
            new_target = XLJiHeConditionExprTransform(known).solver(BasePoly(target)).output[0].sympify()
            target_values = xl_solutions_subs(solutions, new_target)
            self.steps.append(["", "\\therefore%s" % " 或 ".join(
                ["%s = %s" % (new_latex(target), new_latex(v)) for v in target_values])])
            self.output.append(BaseNumbers(target_values))
        else:
            new_target = XLJiHeConditionExprTransform(known).solver(BasePoly(target)).output[0].sympify()
            self.steps.append(["", "\\therefore %s = %s" % (new_latex(target), new_latex(new_target))])
            self.output.append(BaseNumbers([new_target]))
        self.label.add("向量运算-几何法")
        return self


class XLGetExpress007(BaseFunction):
    """
    \\overrightarrow{BA}+\\overrightarrow{AF}+\\overrightarrow{EF}=()
    """
    def solver(self, *args):
        assert len(args) == 1
        assert 'Vequations' not in self.known
        target = args[0].sympify()
        from mathsolver.functions.xiangliang.Vector_Simplify import XLTriangleSimplify
        new_target = XLTriangleSimplify().solver(BaseExpression(target)).output[0].sympify()
        self.steps.append(["", "\\therefore %s = %s" % (new_latex(target), new_latex(new_target))])
        self.output.append(BaseExpression(new_target))
        self.label.add("向量运算-几何法")
        return self


class XLGetExpress(BaseFunction):
    CLS = [XLGetExpress001, XLGetExpress002, XLGetExpress003, XLGetExpress004, XLGetExpress005, XLGetExpress006,
           XLGetExpress007]

    def solver(self, *args):
        known = self.known
        r = None
        for cl in XLGetExpress.CLS:
            try:
                new_known = dict(known)
                r = cl(new_known, verbose=True).solver(*args)
                break
            except Exception:
                pass
        if not r:
            raise 'try fail'
        return r


def get_vector_xiangs(expr):
    p1 = r'Abs_[a-zA-Z]'
    m1 = re.findall(p1, str(expr))
    m1 = list(set(m1))
    p2 = r'Angle_[a-zA-Z][a-zA-Z]'
    m2 = re.findall(p2, str(expr))
    m2 = list(set(m2))
    m = m1 + m2
    return m


# class XLGetExpress(BaseFunction):
#     def solver(self, *args):
#         target = args[0].sympify()
#         target = target.expand()
#         Abs_a = sympify('Abs_a')
#         Abs_b = sympify('Abs_b')
#         Angle_ab = sympify('Angle_ab')
#         new_target = 2 * Abs_a * Abs_b * cos(Angle_ab * pi / 180) - Abs_b * Abs_b
#         target_xiangs = get_vector_xiangs(new_target)
#         assert target_xiangs
#         for target_xiang in target_xiangs:
#             new_item = sympify(target_xiang)
#             new_item_value = self.search(target_xiang)
#             new_target = new_target.subs({new_item: new_item_value})
#         new_target = simplify(new_target)
#         self.steps.append(["", "\\therefore%s = %s" % (latex(target), latex(new_target))])
#         self.output.append(BaseNumber(new_target))
#         return self
